﻿using System;
using System.Collections.Generic;
using System.Management.Automation;
using Microsoft.SharePoint;
using Microsoft.SharePoint.PowerShell;
using Microsoft.SharePoint.Administration;
using System.Globalization;
using System.ComponentModel;
using System.Security.Principal;
using System.Collections.Specialized;
using System.Linq;
using Microsoft.SharePoint.Utilities;


namespace SlamCms.SharePoint.PowerShell
{
	[Cmdlet(VerbsCommon.Copy, "FieldValue")]
	public class SpCmdletCopyFieldValue : SPCmdlet
	{
		[Parameter(Mandatory = true)]
		public string SiteUrl
		{
			get;
			set;
		}

		[Parameter(Mandatory = false)]
		public string ListName
		{
			get;
			set;
		}

		[Parameter(Mandatory = false)]
		public string ContentTypeName
		{
			get;
			set;
		}

		[Parameter(Mandatory = true)]
		public string SourceFieldName
		{
			get;
			set;
		}

		[Parameter(Mandatory = true)]
		public string TargetFieldName
		{
			get;
			set;
		}

		[Parameter(Mandatory = false)]
		public SwitchParameter Preview
		{
			get;
			set;
		}

		[Parameter(Mandatory = false)]
		public SwitchParameter Overwrite
		{
			get;
			set;
		}

		protected override void InternalValidate()
		{
			if (String.IsNullOrEmpty(ListName) && String.IsNullOrEmpty(ContentTypeName))
			{
				base.WriteError(new PSArgumentNullException("ListName", "ListName or ContentTypeName must be specified."), ErrorCategory.InvalidArgument, null);
				base.SkipProcessCurrentRecord();
			}
		}

		protected override void InternalProcessRecord()
		{
			using (SPSite siteCollection = new SPSite(SiteUrl))
			{
				using (SPWeb site = siteCollection.OpenWeb())
				{
					if (site.Exists)
					{
						SPList list = null;
						if (!String.IsNullOrEmpty(ListName))
						{
							list = site.Lists.TryGetList(ListName);
							if (list == null)
							{
								WriteObject("The List '" + ListName + "' was not found in the site: " + site.Title);
								WriteObject("");
							}
						}

						SPContentType contentType = null;
						if (!String.IsNullOrEmpty(ContentTypeName))
						{
							try
							{
								contentType = site.ContentTypes[ContentTypeName];
							}
							catch { }

							if (contentType == null)
							{
								WriteObject("The Content Type '" + ContentTypeName + "' was not found in the site " + site.Title);
								WriteObject("");
							}
						}
						if (Preview)
						{
							WriteObject("Preview Mode");
							WriteObject("");
						}
						if (list != null)
						{
							SPField sourceField = list.Fields.Cast<SPField>().Where(f => f.Title.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase) || f.InternalName.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase) || f.StaticName.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
							SPField targetField = list.Fields.Cast<SPField>().Where(f => f.Title.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase) || f.InternalName.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase) || f.StaticName.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
							CopyListValue(list, sourceField, targetField, contentType != null ? contentType : null);
						}
						else if (contentType != null)
						{
							CopyContentTypeValue(site, contentType);
						}
					}
					else
					{
						WriteObject("Site not found.");
					}
				}
			}
		}

		private void CopyContentTypeValue(SPWeb site, SPContentType contentType)
		{
			foreach (SPList list in site.Lists)
			{
				SPField sourceField = list.Fields.Cast<SPField>().Where(f => f.InternalName.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase) || f.StaticName.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase) || f.Title.Equals(SourceFieldName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
				SPField targetField = list.Fields.Cast<SPField>().Where(f => f.InternalName.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase) || f.StaticName.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase) || f.Title.Equals(TargetFieldName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
				CopyListValue(list, sourceField, targetField, contentType);
			}

			foreach (SPWeb subsite in site.Webs)
			{
				CopyContentTypeValue(subsite, contentType);
				subsite.Dispose();
			}
		}

		private void CopyListValue(SPList list, SPField sourceField, SPField targetField, SPContentType contentType)
		{
			if (sourceField != null)
			{
				if (targetField != null)
				{
					if (!targetField.ReadOnlyField)
					{
						if (list.Items.Count > 0)
						{
							foreach (SPListItem item in list.Items)
							{
								if (contentType == null || item.ContentType.Parent.Name.Equals(contentType.Name))
								{
									bool canCopy = false;

									if (item[sourceField.Id] == null)
									{
										if (item[targetField.Id] == null || Overwrite)
										{
											canCopy = true;
										}
										else if (!Overwrite)
										{
											WriteObject("Item '" + item.Name + "': Cannot copy the Field Value 'null' without setting the -overwrite switch.");
										}
									}
									else if (item[targetField.Id] == null)
									{
										item[targetField.Id] = item[sourceField.Id];
										canCopy = true;
										//bool setBackToNull = false;
										//if (sourceField.TypeDisplayName.Equals(targetField.TypeDisplayName))
										//{
										//    item[targetField.Id] = item[sourceField.Id];
										//    canCopy = true;
										//}
										//else if (targetField.Type.Equals(SPFieldType.Number))
										//{
										//    item[targetField.Id] = targetField.GetFieldValue("0");
										//    setBackToNull = true;
										//}
										//else if (!targetField.Type.Equals(SPFieldType.User))
										//{
										//    item[targetField.Id] = targetField.GetFieldValue("");
										//    setBackToNull = true;
										//}
										//if (targetField.Type.Equals(SPFieldType.User) && sourceField.Type.Equals(SPFieldType.User))
										//{
										//    item[targetField.Id] = item[sourceField.Id];
										//}
										//else if (!targetField.Type.Equals(SPFieldType.User) && !sourceField.Type.Equals(SPFieldType.User))
										//{
										//    try
										//    {
										//        item[targetField.Id] = Convert.ChangeType(item[sourceField.Id], item[targetField.Id].GetType());
										//        canCopy = true;
										//    }
										//    catch (Exception)
										//    {
										//        WriteObject("Item '" + item.Title + "': Cannot convert the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' of Type '" + sourceField.TypeDisplayName + "' into Type '" + targetField.TypeDisplayName + "'.");
										//    }
										//}
										//else
										//{
										//    WriteObject("Item '" + item.Title + "': Cannot convert the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' of Type '" + sourceField.TypeDisplayName + "' into Type '" + targetField.TypeDisplayName + "'.");
										//}

										//if (setBackToNull)
										//{
										//    item[targetField.Id] = null;
										//}
									}
									else if (Overwrite)
									{
										if (sourceField.TypeDisplayName.Equals(targetField.TypeDisplayName) || targetField.Type.Equals(SPFieldType.User) && sourceField.Type.Equals(SPFieldType.User))
										{
											item[targetField.Id] = item[sourceField.Id];
										}
										else if (!targetField.Type.Equals(SPFieldType.User) && !sourceField.Type.Equals(SPFieldType.User))
										{
											try
											{
												item[targetField.Id] = Convert.ChangeType(item[sourceField.Id], item[targetField.Id].GetType());
												canCopy = true;
											}
											catch
											{
												WriteObject("Item '" + item.Title + "': Cannot convert the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' of Type '" + sourceField.TypeDisplayName + "' into Type '" + targetField.TypeDisplayName + "'.");
											}
										}
										else
										{
											WriteObject("Item '" + item.Title + "': Cannot convert the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' of Type '" + sourceField.TypeDisplayName + "' into Type '" + targetField.TypeDisplayName + "'.");
										}
									}
									else
									{
										WriteObject("Item '" + item.Title + "': Cannot copy the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' without setting the -overwrite switch.");
									}
									if (Preview && canCopy)
									{
										WriteObject("Item '" + item.Title + "': Can convert the Field Value '" + Convert.ToString(item[sourceField.Id]) + "' of Type '" + sourceField.TypeDisplayName + "' into Type '" + targetField.TypeDisplayName + "'.");
									}
									else if (canCopy)
									{
										try
										{
											item.Update();
											WriteObject("Item '" + item.Title + "': Successfully updated the Field Value of '" + targetField.Title + "' to '" + Convert.ToString(item[targetField.Id]) + "'.");
										}
										catch (Exception ex)
										{
											WriteObject("Item '" + item.Title + "': Unexpected Error - " + ex.ToString());
										}
									}
								}
							}
						}
					}
					else
					{
						WriteObject("The Target Field '" + TargetFieldName + "' is readonly.");
					}
				}
				else
				{
					WriteObject("The Target Field '" + TargetFieldName + "' was not found in list: " + list.Title);
				}
			}
			else
			{
				WriteObject("The Source Field '" + SourceFieldName + "' was not found in list: " + list.Title);
			}
		}
	}
}
